﻿////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// <copyright>Copyright 2008-2011 Andreas Huber Doenni</copyright>
// Distributed under the GNU General Public License version 2 (GPLv2).
// See accompanying file License.txt or copy at http://phuse.codeplex.com/license.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Phorums
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Threading;
    using Microsoft.Phone.Controls;
    using Microsoft.Phone.Shell;

    using Phuse.Net.Forums;

    /// <summary>The main page of the application.</summary>
    public partial class MainPage : PhoneApplicationPage
    {
        private readonly Style roundButtonStyle;
        private readonly Style fromStyle;
        private readonly Style subjectStyle;

        /// <summary>Initializes a new instance of the <see cref="MainPage"/> class.</summary>
        public MainPage()
        {
            this.InitializeComponent();
            this.roundButtonStyle = (Style)Application.Current.Resources["RoundButton"];
            this.fromStyle = (Style)this.Resources["FromTextBlock"];
            this.subjectStyle = (Style)this.Resources["SubjectTextBlock"];
        }

        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

        private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
        {
            var cache = ((App)Application.Current).Cache;
            var group = cache.Hosts.First().Groups.First();
            SystemTray.ProgressIndicator = new ProgressIndicator() { IsVisible = true, IsIndeterminate = true };
            PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled;
            cache.SendReceiveAsync(new[] { group }, true, CancellationToken.None, new SendReceiveProgress(this.Dispatcher)).ContinueWith(
                task => this.Dispatcher.BeginInvoke(new Action<Task>(this.SendReceiveDone), task), CancellationToken.None);
        }

        private void SendReceiveDone(Task task)
        {
            PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Enabled;
            SystemTray.ProgressIndicator.IsVisible = false;
            task.Wait();
            var group = ((App)Application.Current).Cache.Hosts.First().Groups.First();

            foreach (var article in group.GetOriginalInboundArticles(InboundArticleFilter.NullFilter))
            {
                this.ProcessArticle(this.contentPanel, article);
            }
        }

        private void ProcessArticle(StackPanel parent, IInboundArticle article)
        {
            var panel = new StackPanel() { Orientation = System.Windows.Controls.Orientation.Horizontal };
            var expandButton = new Button() { Style = this.roundButtonStyle, Content = "+" };
            expandButton.Click += this.OnExpandButton_Click;
            panel.Children.Add(expandButton);
            var textPanel = new StackPanel();
            textPanel.Children.Add(new TextBlock() { Style = this.fromStyle, Text = article.From });
            textPanel.Children.Add(new TextBlock() { Style = this.subjectStyle, Text = article.Subject });
            panel.Children.Add(textPanel);
            parent.Children.Add(panel);

            var childrenPanel = new StackPanel() { Margin = new Thickness(72, 0, 0, 0), Tag = article };
            expandButton.Tag = childrenPanel;
            parent.Children.Add(childrenPanel);
        }

        private void OnExpandButton_Click(object sender, RoutedEventArgs e)
        {
            var button = (Button)e.OriginalSource;
            var childrenPanel = (StackPanel)button.Tag;

            if (button.Content.Equals("-"))
            {
                button.Content = "+";
                childrenPanel.Visibility = Visibility.Collapsed;
            }
            else
            {
                button.Content = "-";

                if (childrenPanel.Visibility == Visibility.Collapsed)
                {
                    childrenPanel.Visibility = Visibility.Visible;
                }
                else
                {
                    Task.Factory.StartNew<IEnumerable<IInboundArticle>>(
                        ((IInboundArticle)childrenPanel.Tag).GetFollowupInboundArticles).ContinueWith(
                        task => this.Dispatcher.BeginInvoke(new Action<StackPanel, IEnumerable<IInboundArticle>>(this.ProcessFollowups), childrenPanel, task.Result));
                }
            }
        }

        private void ProcessFollowups(StackPanel childrenPanel, IEnumerable<IInboundArticle> result)
        {
            foreach (var followup in result)
            {
                this.ProcessArticle(childrenPanel, followup);
            }
        }

        /// <summary>Reports send/receive progress in the system tray.</summary>
        private sealed class SendReceiveProgress : IProgress<ISendReceiveProgress>, ISendReceiveProgressVisitor
        {
            private readonly Dispatcher dispatcher;

            ////////////////////////////////////////////////////////////////////////////////////////////////////////////

            /// <summary>See <see cref="IProgress{T}.Report"/>.</summary>
            public void Report(ISendReceiveProgress value)
            {
                value.Accept(this);
            }

            /// <summary>See <see cref="IVisitor{T,U}.OnVisit"/>.</summary>
            public void OnVisit(ISendReceiveProgress visitable)
            {
                throw new NotImplementedException("Unexpected progress.");
            }

            /// <summary>See <see cref="IVisitor{T,U}.OnVisit"/>.</summary>
            public void OnVisit(ConnectProgress visitable)
            {
                this.ReportProgress(true, visitable.Percent, "Connecting to " + visitable.HostName + "...");
            }

            /// <summary>See <see cref="IVisitor{T,U}.OnVisit"/>.</summary>
            public void OnVisit(SendProgress visitable)
            {
                this.ReportProgress(false, visitable.Percent, "Sending...");
            }

            /// <summary>See <see cref="IVisitor{T,U}.OnVisit"/>.</summary>
            public void OnVisit(HeaderReceiveProgress visitable)
            {
                this.ReportProgress(false, visitable.Percent, "Receiving " + visitable.DisplayName + " Headers...");
            }

            /// <summary>See <see cref="IVisitor{T,U}.OnVisit"/>.</summary>
            public void OnVisit(ContentReceiveProgress visitable)
            {
                this.ReportProgress(false, visitable.Percent, "Receiving " + visitable.DisplayName + " Contents...");
            }

            ////////////////////////////////////////////////////////////////////////////////////////////////////////////

            internal SendReceiveProgress(Dispatcher dispatcher)
            {
                this.dispatcher = dispatcher;
            }

            ////////////////////////////////////////////////////////////////////////////////////////////////////////////

            private void ReportProgress(bool isIndeterminate, int percent, string message)
            {
                this.dispatcher.BeginInvoke(
                    () =>
                    {
                        var indicator = SystemTray.ProgressIndicator;

                        if (indicator == null)
                        {
                            // TODO: This might probably happen if we change the page during download.
                            return;
                        }

                        indicator.IsIndeterminate = isIndeterminate;
                        indicator.Value = (double)percent / 100.0;
                        indicator.Text = message;
                    });
            }
        }
    }
}